﻿using System.Text;

namespace HHFileViewServer
{
    /// <summary>
    /// 文件帮助类
    /// </summary>
    public static class FileHelper
    {
        /// <summary>
        /// 通过文件后缀判断类型
        /// </summary>
        /// <param name="extension"></param>
        /// <returns></returns>
        public static (string extension, FILETYPE fileType) JudgeFileType(string extension)
        {
            extension = extension.ToLower();
            if (extension == ".jpg" || extension == ".png" || extension == ".gif" || extension == ".jpeg")
            {
                return (extension, FILETYPE.IMAGE);
            }
            if (extension == ".html")
            {
                return (extension, FILETYPE.HTML);
            }
            if (extension == ".xls" || extension == ".xlsx" || extension == ".doc" || extension == ".docx" || extension == ".ppt" || extension == ".pptx")
            {
                return (extension, FILETYPE.OFFICE);
            }
            if (extension == ".pdf")
            {
                return (extension, FILETYPE.PDF);
            }
            if (extension == ".rar" || extension == ".zip" || extension == ".7z")
            {
                return (extension, FILETYPE.COMPRESS);
            }
            return (string.Empty, FILETYPE.OTHER);
        }

        /// <summary>
        /// 根据文件字节判断文件类型
        /// </summary>
        /// <param name="magicNumber"></param>
        /// <returns></returns>
        public static (string extension, FILETYPE fileType) JudgeFileType(byte[] buffer)
        {
            string extension = string.Empty;

            int len = FILE_TYPE_MAP.Keys.Max(x => int.Parse(x)).ToString().Length;
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < len; i++)
            {
                int v = buffer[i] & 0xFF;
                String hv = v.ToString();
                if (hv.Length < 2)
                {
                    stringBuilder.Append(0);
                }
                stringBuilder.Append(hv);
            }
            len = stringBuilder.Length;
            while (len > 0)
            {
                var str = stringBuilder.ToString().Substring(0, len).ToString();
                if (FILE_TYPE_MAP.Any(x => x.Key == str))
                {
                    extension = FILE_TYPE_MAP[str];
                    break;
                }
                len -= 1;
            }

            if (string.IsNullOrEmpty(extension))
                return (string.Empty, FILETYPE.OTHER);

            return JudgeFileType(extension);
        }

        /// <summary>
        /// 获取下载地址的文件名
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static string GetFileName(string url)
        {
            int index = url.IndexOf("?");
            int lastIndex = url.Substring(0, index).LastIndexOf("/") + 1;
            if (index <= -1)
            {
                index = url.Length;
            }
            return url.Substring(lastIndex, (index - lastIndex));
        }

        /// <summary>
        /// 处理LibreOffice路径
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static string HandlePathByLibreOffice(string path)
        {
            return path
                .Replace("//", "/")
                .Replace(@"\\", "/")
                .Replace(@"\", "/");
        }

        /// <summary>
        /// 获取文件流字节数组
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public async static Task<(byte[] bytes, int length)> StreamToByte(this Stream stream)
        {
            byte[] buffer = new byte[stream.Length];
            int readLength = 0;
            int length;
            while ((length = await stream.ReadAsync(buffer, 0, buffer.Length)) != 0)
            {
                readLength += length;
            }
            return (buffer, readLength);
        }

        /// <summary>
        /// 判断是否是本地文件
        /// </summary>
        /// <param name="host">本地的Host</param>
        /// <param name="url">下载地址</param>
        /// <returns></returns>
        public static (bool isLocal, string path) IsLocalFile(string host, string url)
        {
            // 后面加缓存实现，现在先简单判断host
            if (url.ToLower().Contains(host.ToLower()))
            {
                return (true, url.Replace(host, "").Replace("/file", ServerOp.ServerConfig.DownloadPath));
            }
            return (false, string.Empty);
        }

        /// <summary>
        /// 获取本地文件信息
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static BaseFileInfo GetLocalFile(string path)
        {
            bool isFile = File.Exists(path);
            bool isFolder = Directory.Exists(path);
            if (!isFile && !isFolder)
                throw new CustomException("文件不存在");

            if (isFile)
            {
                var fileInfo = new FileInfo(path);
                var type = JudgeFileType(fileInfo.Extension.ToLower());
                return new BaseFileInfo()
                {
                    Name = fileInfo.Name,
                    Extension = type.extension,
                    AbsolutePath = fileInfo.FullName,
                    Path = Const.RelativePath(fileInfo.Name),
                    FileType = type.fileType,
                };
            }
            else
            {
                return new BaseFileInfo()
                {
                    FileType = FILETYPE.FOLDER,
                    Files = GetFolderFiles(String.Empty, path)
                };
            }
        }

        /// <summary>
        /// 获取文件夹下所有文件
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static List<BaseFileInfo> GetFolderFiles(string folder, string path)
        {
            if (string.IsNullOrEmpty(folder))
            {
                folder = path.Replace(ServerOp.ServerConfig.DownloadPath, "");
            }
            // 列出解压地址下的所有文件
            DirectoryInfo dirInfo = new DirectoryInfo(path);
            FileInfo[] fileInfos = dirInfo.GetFiles();
            DirectoryInfo[] directoryInfos = dirInfo.GetDirectories();
            List<BaseFileInfo> fileTypeModels = new List<BaseFileInfo>();
            foreach (var dir in directoryInfos)
            {
                fileTypeModels.Add(new BaseFileInfo()
                {
                    Extension = string.Empty,
                    FileType = FILETYPE.FOLDER,
                    Icon = "folder.png",
                    Name = dir.Name,
                    Path = Const.RelativePath(folder + "/" + dir.Name)
                });
            }
            foreach (var file in fileInfos)
            {
                var fileTypeModel = FileHelper.JudgeFileType(file.Extension);
                var fileInfo = new BaseFileInfo()
                {
                    Name = file.Name,
                    FileType = fileTypeModel.fileType,
                    Path = Const.RelativePath(folder + "/" + file.Name)
                };
                if (FileHelper.FILE_ICON_MAP.Any(x => x.Key == file.Extension.ToLower()))
                {
                    fileInfo.Icon = FileHelper.FILE_ICON_MAP[file.Extension.ToLower()];
                }
                else
                {
                    // 默认全部归于文本
                    fileInfo.Icon = "txt.png";
                }
                fileTypeModels.Add(fileInfo);
            }
            return fileTypeModels;
        }

        /// <summary>
        /// 文件魔数-后缀映射
        /// </summary>
        /// <returns></returns>
        private static Dictionary<string, string> FILE_TYPE_MAP = new Dictionary<string, string>()
        {
            {"255216", ".jpg"},
            {"7173", ".gif"},
            {"6677", ".bmp"},
            {"13780", ".png"},
            //{"7790", "COM"},
            //{"7790", "EXE"},
            //{"7790", "DLL"},
            {"8297", ".rar"},
            {"8075", ".zip"},
            {"6063", ".xml"},
            {"6033", ".html"},
            {"239187", ".aspx"},
            {"117115", ".cs"},
            {"119105", ".js"},
            {"210187", ".txt"},
            {"255254", ".sql"},
            {"64101", ".bat"},
            {"10056", ".btseed"},
            //{"255254", "RDP"},
            {"5666", ".psd"},
            {"3780", ".pdf"},
            {"7384", ".chm"},
            {"70105", ".log"},
            {"8269", ".reg"},
            {"6395", ".hlp"},
            {"208207", ".xlsx"},
            {"807503042", ".xlsx"}
        };

        /// <summary>
        /// 后缀名与图标映射关系
        /// </summary>
        private static Dictionary<string, string> FILE_ICON_MAP = new Dictionary<string, string>()
        {
            { ".html" , "chrome.svg" },
            { ".png" , "image.png" },
            { ".gif" , "image.png" },
            { ".jpg" , "image.png" },
            { ".jpeg" , "image.png" },
            { ".pdf" , "pdf.png" },
            { ".xls" , "excel.png" },
            { ".xlsx" , "excel.png" },
            { ".doc" , "word.png" },
            { ".docx" , "word.png" },
            { ".ppt" , "ppt.png" },
            { ".pptx" , "ppt.png" },
            { ".rar" , "rar.png" },
            { ".zip" , "rar.png" },
            { ".7z" , "rar.png" }
    };
    }

    /// <summary>
    /// 文件类型
    /// </summary>
    public enum FILETYPE
    {
        // 未知文件
        OTHER = 0,
        // 图片
        IMAGE,
        // PDF
        PDF,
        // 网页
        HTML,
        // 办公文件
        OFFICE,
        // 压缩文件
        COMPRESS,
        // 压缩文件（密码）
        PASSWORD,
        // 文件夹
        FOLDER
    }
}
